package com.my.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.my.apis.article.IArticleClient;
import com.my.common.constans.WemediaConstants;
import com.my.common.constans.WmNewsMessageConstants;
import com.my.common.exception.CustomException;
import com.my.model.admin.dtos.NewsAuditDto;
import com.my.model.admin.dtos.WeMediaDto;
import com.my.model.admin.dtos.WmNewsAuditRespDto;
import com.my.model.common.dtos.PageResponseResult;
import com.my.model.common.dtos.ResponseResult;
import com.my.model.common.enums.AppHttpCodeEnum;
import com.my.model.wemedia.dtos.WmNewsDto;
import com.my.model.wemedia.dtos.WmNewsPageReqDto;
import com.my.model.wemedia.pojos.WmMaterial;
import com.my.model.wemedia.pojos.WmNews;
import com.my.model.wemedia.pojos.WmNewsMaterial;
import com.my.model.wemedia.pojos.WmUser;
import com.my.utils.thread.WmThreadLocalUtils;
import com.my.wemedia.mapper.WmMaterialMapper;
import com.my.wemedia.mapper.WmNewsMapper;
import com.my.wemedia.mapper.WmNewsMaterialMapper;
import com.my.wemedia.service.WmAutoScanService;
import com.my.wemedia.service.WmNewsService;
import com.my.wemedia.service.WmNewsTaskService;
import com.my.wemedia.service.WmUserService;
import com.sun.corba.se.spi.ior.ObjectKey;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {
    /**
     * 查找文章内容
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findContentList(WmNewsPageReqDto dto) {
        //1.参数检查
        dto.checkParam();

        //2.分页条件查询
        IPage<WmNews> page = new Page<>(dto.getPage(),dto.getSize());
        LambdaQueryWrapper<WmNews> lqw = new LambdaQueryWrapper<>();

        //状态查询
        lqw.eq(dto.getStatus() != null,WmNews::getStatus,dto.getStatus());

        //频道精确查询
        lqw.eq(dto.getChannelId() != null,WmNews::getChannelId,dto.getChannelId());

        //时间范围查询
        if(dto.getBeginPubDate() != null && dto.getEndPubDate() != null) {
            lqw.between(WmNews::getPublishTime,dto.getBeginPubDate(),dto.getEndPubDate());
        }

        //关键字模糊查询
        lqw.eq(dto.getKeyword() != null,WmNews::getContent,dto.getKeyword());

        //查询当前登录人的文章
        lqw.eq(WmNews::getUserId, WmThreadLocalUtils.getUser().getId());

        //按照发布时间倒序排序
        lqw.orderByDesc(WmNews::getPublishTime);

        page = page(page, lqw);

        //3.结果返回
        ResponseResult responseResult = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
        responseResult.setData(page.getRecords());

        return responseResult;
    }

    @Autowired
    private KafkaTemplate<String,String> kafkaTemplate;
    /**
     * 文章下架或上架
     * @param id
     * @param enable
     * @return
     */
    @Override
    public ResponseResult downOrUp(Integer id,Integer enable) {
        log.info("执行文章上下架操作...");
        if(id == null || enable == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //根据id获取文章
        WmNews news = getById(id);
        if(news == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"文章信息不存在");
        }
        //获取当前文章状态
        Short status = news.getStatus();
        if(!status.equals(WmNews.Status.PUBLISHED.getCode())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"文章非发布状态，不能上下架");
        }

        //更改文章状态
        news.setEnable(enable.shortValue());
        updateById(news);
        log.info("更改文章上架状态{}-->{}",status,news.getEnable());

        //发送消息到Kafka
        Map<String, Object> map = new HashMap<>();
        map.put("articleId",news.getArticleId());
        map.put("enable",enable.shortValue());
        kafkaTemplate.send(WmNewsMessageConstants.WM_NEWS_UP_OR_DOWN_TOPIC,JSON.toJSONString(map));
        log.info("发送消息到Kafka...");

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    @Autowired
    private WmAutoScanService wmAutoScanService;
    @Autowired
    private WmNewsTaskService wmNewsTaskService;
    /**
     * 提交文章
     * @param dto
     * @return
     */
    @Override
    public ResponseResult submitNews(WmNewsDto dto) throws Exception {
        //1.参数校验
        if(dto == null || dto.getContent().length() == 0) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //2.保存或修改文章
        //2.1属性拷贝
        WmNews wmNews = new WmNews();
        BeanUtils.copyProperties(dto,wmNews);

        //2.2设置封面图片
        if(dto.getImages() != null && dto.getImages().size() != 0) {
            String images = StringUtils.join(dto.getImages(), ",");
            wmNews.setImages(images);
        }

        //2.3封面类型为自动
        if(dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)) {
            wmNews.setType(null);
        }

        saveOrUpdateWmNews(wmNews);

        //3.判断是否为草稿
        if(dto.getStatus().equals(WmNews.Status.NORMAL.getCode())) {
            //直接保存结束
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        }

        //4.不是草稿
        //4.1保存文章图片素材与文章关系
        //4.1.1提取图片素材列表
        List<String> imagesList = getImagesList(dto);
        //4.1.2保存
        saveRelatedImages(imagesList,wmNews.getId(),WemediaConstants.WM_CONTENT_REFERENCE);

        //4.2保存封面图片和文章关系
        saveRelatedCover(dto,imagesList,wmNews);

        //5.审核文章(异步调用)
        // wmAutoScanService.AutoScanTextAndImage(wmNews.getId());
        //5.将任务添加到延迟服务
        wmNewsTaskService.addNewsToTask(wmNews.getId(),wmNews.getPublishTime());

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;

    private void saveOrUpdateWmNews(WmNews wmNews) {
        wmNews.setUserId(WmThreadLocalUtils.getUser().getId());
        wmNews.setCreatedTime(new Date());
        wmNews.setSubmitedTime(new Date());
        wmNews.setEnable((short) 1);

        if(wmNews.getId() == null) {
            //保存
            save(wmNews);
        } else {
            //修改
            //删除文章和素材的关系
            wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId,wmNews.getId()));
            updateById(wmNews);
        }
    }

    /**
     * 获取文章图片素材列表
     * @param dto
     * @return
     */
    private List<String> getImagesList(WmNewsDto dto) {
        List<String> imagesUrlList = new ArrayList<>();
        String content = dto.getContent();
        List<Map> maps = JSON.parseArray(content, Map.class);
        for(Map map : maps) {
            if(map.get("type").equals("image")) {
                String imageUrl = (String) map.get("value");
                imagesUrlList.add(imageUrl);
            }
        }
        return imagesUrlList;
    }

    @Autowired
    private WmMaterialMapper wmMaterialMapper;
    /**
     * 保存图片素材与文章的关系
     * @param imagesList
     * @param id
     */
    private void saveRelatedImages(List<String> imagesList, Integer id,Short type) {
        //参数校验
        if(imagesList != null && !imagesList.isEmpty()) {
            //通过图片url获取素材id
            List<WmMaterial> materials = wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, imagesList));
            //判断素材是否有效
            if(materials == null || materials.isEmpty()) {
                //手动抛出异常 一方面提醒开发者，另一方面做数据回滚
                throw new CustomException(AppHttpCodeEnum.MATERIASL_REFERENCE_FAIL);
            }

            //素材部分失效
            if(materials.size() != imagesList.size()) {
                throw new CustomException(AppHttpCodeEnum.MATERIASL_REFERENCE_FAIL);
            }

            //获取素材id
            List<Integer> materialsId = materials.stream().map(WmMaterial::getId).collect(Collectors.toList());

            //批量保存
            wmNewsMaterialMapper.saveRelations(materialsId,id,type);
        }
    }

    /**
     * 保存封面图片与文章之间关系
     * @param dto
     * @param imagesList
     * @param wmNews
     */
    private void saveRelatedCover(WmNewsDto dto, List<String> imagesList, WmNews wmNews) {
        List<String> images = dto.getImages();

        //自动设置封面
        if(dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)) {
            //多图
            if(imagesList.size() >= 3) {
                //设置文章封面属性
                wmNews.setType(WemediaConstants.WM_NEWS_MANY_IMAGE);
                images = imagesList.stream().limit(3).collect(Collectors.toList());
            }
            //单图
            else if(imagesList.size() >= 1) {
                //设置文章封面属性
                wmNews.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE);
                images = imagesList.stream().limit(1).collect(Collectors.toList());
            }
            //无图
            else {
                //设置文章封面属性
                wmNews.setType(WemediaConstants.WM_NEWS_NONE_IMAGE);
            }

            //修改文章封面信息
            if(images != null && images.size() != 0) {
                wmNews.setImages(StringUtils.join(images,","));
            }
            updateById(wmNews);
        }
        if(images != null && images.size() != 0) {
            saveRelatedImages(images,wmNews.getId(),WemediaConstants.WM_COVER_REFERENCE);
        }
    }

    /**
     * 修改文章入口
     * @param id
     * @return
     */
    @Override
    public ResponseResult modifyArticleApi(Integer id) {
        if(id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //根据文章id获取文章信息
        WmNews wmNews = this.getById(id);
        return ResponseResult.okResult(wmNews);
    }

    @Resource
    private IArticleClient articleClient;
    /**
     * 删除文章
     * @param id
     * @return
     */
    @Override
    public ResponseResult deleteArticle(Integer id) {
        //1.参数校验
        if(id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //2.删除素材和文章关系
        log.info("删除素材和文章关系数据...");
        wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId,id));

        //3.获取app端文章id
        WmNews wmNews = getById(id);
        if(wmNews != null && wmNews.getArticleId() != null) {
            //4.删除app端文章
            log.info("远程调用删除app端文章...");
            articleClient.deleteArticle(wmNews.getArticleId());
        }

        //5.根据id删除文章
        log.info("删除文章...");
        this.removeById(id);

        log.info("成功删除id为{}的文章",id);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    @Autowired
    private WmUserService wmUserService;
    /**
     * 管理端媒体审核
     * @param weMediaDto
     * @return
     */
    @Override
    public ResponseResult auditWmNews(WeMediaDto weMediaDto) {
        if(weMediaDto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        IPage<WmNews> page = new Page<>(weMediaDto.getPage(),weMediaDto.getSize());
        LambdaQueryWrapper<WmNews> lqw = new LambdaQueryWrapper<>();
        lqw.like(StringUtils.isNotBlank(weMediaDto.getTitle()),WmNews::getTitle,weMediaDto.getTitle());
        lqw.eq(weMediaDto.getStatus() != null,WmNews::getStatus,weMediaDto.getStatus());
        IPage<WmNews> iPage = page(page, lqw);

        //设置作者名称
        List<WmNewsAuditRespDto> list = new ArrayList<>();
        for (WmNews record : iPage.getRecords()) {
            WmNewsAuditRespDto wmNewsAuditRespDto = new WmNewsAuditRespDto();
            BeanUtils.copyProperties(record,wmNewsAuditRespDto);

            //获取作者信息
            WmUser wmUser = wmUserService.getById(record.getUserId());
            if(wmUser == null) {
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"查询不到作者信息");
            }
            wmNewsAuditRespDto.setAuthorName(wmUser.getName());

            list.add(wmNewsAuditRespDto);
        }

        ResponseResult re = new PageResponseResult(weMediaDto.getPage(), weMediaDto.getSize(), (int) iPage.getTotal());
        re.setCode(200);
        re.setData(list);

        return re;
    }

    /**
     * 管理端查看文章信息
     * @param id
     * @return
     */
    @Override
    public ResponseResult getOneNews(Integer id) {
        if(id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        WmNews wmNews = getById(id);
        WmNewsAuditRespDto wmNewsAuditRespDto = new WmNewsAuditRespDto();
        BeanUtils.copyProperties(wmNews,wmNewsAuditRespDto);

        //获取作者信息
        WmUser wmUser = wmUserService.getById(wmNews.getUserId());
        if(wmUser == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"作者信息不存在");
        }
        wmNewsAuditRespDto.setAuthorName(wmUser.getName());

        return ResponseResult.okResult(wmNewsAuditRespDto);
    }

    /**
     * 人工审核通过
     * @param dto
     * @return
     */
    @Override
    public ResponseResult auditPass(NewsAuditDto dto) {
        if(dto == null || dto.getId() == null || dto.getStatus() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //更改文章状态
        log.info("文章{}人工审核通过",dto.getId());
        WmNews wmNews = getById(dto.getId());
        wmNews.setStatus(WmNews.Status.PUBLISHED.getCode());
        updateById(wmNews);

        //保存文章
        log.info("保存文章到App端...");
        ResponseResult responseResult = wmAutoScanService.saveAppArticle(wmNews);
        if(!responseResult.getCode().equals(200)) {
            throw new RuntimeException("人工审核，保存文章失败");
        }

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 人工审核不通过
     * @param dto
     * @return
     */
    @Override
    public ResponseResult auditFail(NewsAuditDto dto) {
        if(dto == null || dto.getId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        WmNews wmNews = getById(dto.getId());
        wmNews.setStatus(WmNews.Status.FAIL.getCode());
        if(StringUtils.isNotBlank(dto.getMsg())) {
            wmNews.setReason(dto.getMsg());
        }
        updateById(wmNews);

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }
}
